package de.tum.in.eist.im.client.Chat.ChatChannel;

import java.util.Date;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DockPanel;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;

import de.tum.in.eist.im.shared.Message.Message;
import de.tum.in.eist.im.shared.User.User;

/**
 * TODO:
 * @author Robert Weindl
 * save user of a channel in a list on the server and display them in the list
 *
 */

public class ChatMessageHandler {
	
	// private variables
	private final ChatMessageHandlerServiceAsync chatMessageHandlerService = GWT.create(ChatMessageHandlerService.class);
	private Long chatChannelId;
	private VerticalPanel verticalPanel = new VerticalPanel();
	private VerticalPanel userVerticalPanel = new VerticalPanel();
	private final User user;
	
	// private variables for the send module
	private final TextBox sendMessageBox = new TextBox();
	private final Button sendMessageButton = new Button();
	private final Label sendMessageError = new Label();
	
	/**
	 * create an instance of the ChatMessageHandler and restore old messages
	 * @param chatId id of the channel
	 */
	public ChatMessageHandler(Long chatId, User user) {
		this.chatChannelId = chatId;
		this.user = user;
		
		// add user to list of user in channel
		this.addUserAsOnline();
		this.addUserAsOnlineToPrivate();
		
		// start the user in channel cyclus
		this.getOnlineUsersFromServer();
		
		// call the server to get old messages in the current channel
		chatMessageHandlerService.getMessagesFromDatabase(
			this.chatChannelId,
			new AsyncCallback<Message[]>() {
				
				public void onFailure(Throwable caught) {
					System.out.println(">>> ChatPanelHandler: cannot get messages!");
				}
				
				public void onSuccess(Message[] result) {
					if (result != null) {
						for (int i = 0; i < result.length; i++) {
							ChatMessageHandler.this.addChatMessage(result[i]);
						}
					}
				}
			});
	}
	
	/** 
	 * create the simple panel for the messages
	 * @return the Widget for the display of the messages
	 */
	public Widget getWidget() {
		DockPanel dock = new DockPanel();
		
	    // Add scrollable text in the center
	    ScrollPanel scroller = new ScrollPanel(verticalPanel);
	    scroller.setSize("600px", "600px");
	    scroller.scrollToBottom();
	    dock.add(scroller, DockPanel.CENTER);
		dock.add(userVerticalPanel, DockPanel.EAST);

		return dock;
	}
	
	/**
	 * create a widget to create messages
	 * @return the widget to send messages
	 */
	public Widget getSendMessageWidget() {
		
		// create horizontal panel
		HorizontalPanel horizontalPanel = new HorizontalPanel();
		
		// set labels
		sendMessageBox.setText("Please enter the message!");
		sendMessageButton.setText("Send");
		sendMessageError.setText("");
		
		horizontalPanel.add(sendMessageBox);
		horizontalPanel.add(sendMessageButton);
		horizontalPanel.add(sendMessageError);
		
		// create vertical panel
		VerticalPanel verticalPanel = new VerticalPanel();
		verticalPanel.add(horizontalPanel);
		// verticalPanel.add(sendMessageError);
		
		// create handler
		sendMessageBox.addKeyUpHandler(new KeyUpHandler() {
			@Override
			public void onKeyUp(KeyUpEvent event) {
				if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
					ChatMessageHandler.this.sendMessageToServer();
				}	
			}
		});
		
		sendMessageButton.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				ChatMessageHandler.this.sendMessageToServer();		
			}	
		});
		
		return verticalPanel;
	}
	
	/**
	 * send the message of the sendMessageBox to the server
	 */
	public void sendMessageToServer() {
		this.sendMessageError.setText("");
		
		if (this.sendMessageBox.getText().equals("")) {
			this.sendMessageError.setText("You cannot send an empty Message!");
		} else {
			this.sendMessageButton.setEnabled(false);
			
			Message sendMessage = new Message(this.sendMessageBox.getText(), this.user, new Date(), this.chatChannelId);
			
			// send message to the server
			chatMessageHandlerService.sendMessage(
				sendMessage,
				new AsyncCallback<Boolean>() {
					public void onFailure(Throwable caught) {
						ChatMessageHandler.this.sendMessageError.setText(caught.getMessage());
						ChatMessageHandler.this.sendMessageButton.setEnabled(true);
					}
					
					public void onSuccess(Boolean result) {
						if (result) {
							ChatMessageHandler.this.sendMessageButton.setEnabled(true);
							ChatMessageHandler.this.sendMessageBox.setText("");
						} else {
							ChatMessageHandler.this.sendMessageError.setText("An Error occured while sending the message");
						}
					}
				});
		}
	}
	
	/**
	 * add a new message to the message panel
	 * @param message the message which should be displayed
	 */
	public void addChatMessage(Message message) {
		HorizontalPanel horizontalPanel = new HorizontalPanel();
		Label messageLabel = new Label();
		messageLabel.setText(">>> " + message.getMessageUser().getUsername() + ": " + message.getMessageText());
		horizontalPanel.add(messageLabel);
		verticalPanel.add(horizontalPanel);
	}
	
	/**
	 * add a user to the list of online users in the current! group
	 */
	public void addUserAsOnline() {
		// add user to channel
		chatMessageHandlerService.addUserAsOnline(
			user,
			chatChannelId,
			new AsyncCallback<Boolean>() {
				public void onFailure(Throwable caught) {
					System.out.println(">>> ChatPanelHandler: cannot add user to list!");
				}
				
				public void onSuccess(Boolean result) {
					// display panel with all user and start push for user session
				}
			});
	}
	
	/**
	 * add a user online to the list of all online users in the current! private group
	 */
	public void addUserAsOnlineToPrivate() {
		// add user to channel
		chatMessageHandlerService.addUserAsOnlineToPrivate(
			user,
			chatChannelId,
			new AsyncCallback<Boolean>() {
				public void onFailure(Throwable caught) {
					System.out.println(">>> ChatPanelHandler: cannot add user to list!");
				}
				
				public void onSuccess(Boolean result) {
					// display panel with all user and start push for user session
				}
			});	
	}
	
	/**
	 * remove a user of the list of users in the current! group
	 */
	public void removeUserAsOnline() {
		// FIX: remove user from channel if he close the tab
		chatMessageHandlerService.removeUserAsOnline(
				user, 
				chatChannelId,
				new AsyncCallback<Boolean>() {
					public void onFailure(Throwable caught) {
						System.out.println(" cannot remove user from list!");
					}
					
					public void onSuccess(Boolean result) {
						
					}
				}
		);
	}
	
	/**
	 * Poll the list of users in the chat panel and display them on the list of users in the chat panel
	 * So we implemented a push system and a poll system
	 * Why do we need a poll here: The push system creates threads on the server we cannot be sure
	 * that one connection can create multiple threads on the server
	 */
	public void getOnlineUsersFromServer() {
		/*
		Timer timer = new Timer() {
			@Override
			public void run() {
				chatMessageHandlerService.getOnlineUsersFromServer(
						chatChannelId,
						new AsyncCallback<List<User>>() {
							@Override
							public void onFailure(Throwable caught) {
								System.out.println("Error in getOnlineUsersFromServer()");
							}

							@Override
							public void onSuccess(List<User> result) {
								userVerticalPanel.clear();
								for (User u : result) {
									userVerticalPanel.add(new Label(u.getUsername()));
								}
								ChatMessageHandler.this.getOnlineUsersFromServer();
							}	
						}
				);	
			}
		};
		// poll for users every 0.5 seconds
		timer.schedule(500);
		*/
	}
	
	/**
	 * get the vertical panel
	 * @return the vertical panel
	 */
	public VerticalPanel getVerticalPanel() {
		return this.verticalPanel;
	}

	/**
	 * returns the id of the chat channel which created this object
	 * @return the id of the chat channel which created this object
	 */
	public Long getChatChannelId () {
		return this.chatChannelId;
	}
}
